/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { BaseStruct } from './BaseStruct.js';
import { Rect } from '../component/trace/timer-shaft/Rect.js';
import { Utils } from '../component/trace/base/Utils.js';

const padding = 1;

export class ThreadStruct extends BaseStruct {
  static runningColor: string = '#467b3b';
  static rColor = '#a0b84d';
  static uninterruptibleSleepColor = '#f19d38';
  static sColor = '#FBFBFB';
  static hoverThreadStruct: ThreadStruct | undefined;
  static selectThreadStruct: ThreadStruct | undefined;
  hasSched: number | undefined;
  pid: number | undefined;
  processName: string | undefined;
  threadName: string | undefined;
  tid: number | undefined;
  upid: number | undefined;
  utid: number | undefined;
  cpu: number | undefined;
  dur: number | undefined;
  end_ts: number | undefined;
  id: number | undefined;
  is_main_thread: number | undefined;
  name: string | undefined;
  startTime: number | undefined;
  start_ts: number | undefined;
  state: string | undefined;
  type: string | undefined;

  static draw(ctx: CanvasRenderingContext2D, data: ThreadStruct) {
    if (data.frame) {
      ctx.globalAlpha = 1;
      let stateText = data.state || '';
      if ('S' == data.state) {
        ctx.fillStyle = ThreadStruct.sColor;
        ctx.globalAlpha = 0.2; // transparency
        ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2);
        ctx.globalAlpha = 1; // transparency
      } else if ('R' == data.state) {
        ctx.fillStyle = ThreadStruct.rColor;
        ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2);
        ctx.fillStyle = '#fff';
        ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
      } else if ('D' == data.state) {
        ctx.fillStyle = ThreadStruct.uninterruptibleSleepColor;
        ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2);
        ctx.fillStyle = '#fff';
        ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
      } else if ('Running' == data.state) {
        ctx.fillStyle = ThreadStruct.runningColor;
        ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2);
        ctx.fillStyle = '#fff';
        ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
      } else {
        ctx.fillStyle = ThreadStruct.rColor;
        ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2);
        ctx.fillStyle = '#fff';
        ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame);
      }
      if (
        ThreadStruct.selectThreadStruct &&
        ThreadStruct.equals(ThreadStruct.selectThreadStruct, data) &&
        ThreadStruct.selectThreadStruct.state != 'S'
      ) {
        ctx.strokeStyle = '#232c5d';
        ctx.lineWidth = 2;
        ctx.strokeRect(data.frame.x, data.frame.y + padding, data.frame.width - 2, data.frame.height - padding * 2);
      }
    }
  }

  static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect) {
    let textMetrics = ctx.measureText(str);
    let charWidth = Math.round(textMetrics.width / str.length);
    if (textMetrics.width < frame.width - textPadding * 2) {
      let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding);
      ctx.textBaseline = 'middle';
      ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2), frame.width - textPadding * 2);
      return;
    }
    if (frame.width - textPadding * 2 > charWidth * 4) {
      let chatNum = (frame.width - textPadding * 2) / charWidth;
      let x1 = frame.x + textPadding;
      ctx.textBaseline = 'middle';
      ctx.fillText(
        str.substring(0, chatNum - 4) + '...',
        x1,
        Math.floor(frame.y + frame.height / 2),
        frame.width - textPadding * 2
      );
      return;
    }
  }

  static getEndState(state: string): string {
    let statusMapElement = Utils.getEndState(state);
    if (statusMapElement) {
      return statusMapElement;
    } else {
      if ('' == statusMapElement || statusMapElement == null) {
        return '';
      }
      return 'Unknown State';
    }
  }

  static equals(d1: ThreadStruct, d2: ThreadStruct): boolean {
    if (
      d1 &&
      d2 &&
      d1.cpu == d2.cpu &&
      d1.tid == d2.tid &&
      d1.state == d2.state &&
      d1.startTime == d2.startTime &&
      d1.dur == d2.dur
    ) {
      return true;
    } else {
      return false;
    }
  }
}
